﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using MyUtility;

namespace MySerialPort.ClassFiles
{
    public class mySerialPort : IDisposable
    {
        public enum SerialPortStatus
        {
            Open,
            Null,
            Close
        }

        private SerialPort _com;
        private bool _usingQueue;
        private List<byte> _data;
        List<byte> _msgBuffer;
//        private Queue<List<byte>> _msgQueue;

        //public Queue<List<byte>> MsgQueue
        //{
        //    get { return _msgQueue; }
        //    set { _msgQueue = value; }
        //}
        public List<byte> Data
        {
            get
            {
                lock (ReceiveBufferLock)
                {
                    return _data;
                }
            }
        }

        private readonly object ReceiveBufferLock = new object();
        public bool UsingQueue
        {
            get { return _usingQueue; }
            set { _usingQueue = value; }
        }


        public delegate void SerialPortOutputDelegate(object obj);
        private SerialPortOutputDelegate _serialPortOutputHander;

        #region ///Dispose
        //供程序员显式调用的Dispose方法
        public void Dispose()
        {
            _com.Dispose();
            //调用带参数的Dispose方法，释放托管和非托管资源
            Dispose(true);
            //手动调用了Dispose释放资源，那么析构函数就是不必要的了，这里阻止GC调用析构函数
            System.GC.SuppressFinalize(this);
        }

        //protected的Dispose方法，保证不会被外部调用。
        //传入bool值disposing以确定是否释放托管资源
        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                _com.Dispose();  ///TODO:在这里加入清理"托管资源"的代码，应该是xxx.Dispose();
            }
            ///TODO:在这里加入清理"非托管资源"的代码
        }

        //供GC调用的析构函数
        ~mySerialPort()
        {
            Dispose(false);//释放非托管资源
        }
        #endregion


        public SerialPortStatus IsConnected()
        {

            if (_com != null)
                if (_com.IsOpen)
                    return SerialPortStatus.Open;
                else
                    return SerialPortStatus.Close;
            else
                return SerialPortStatus.Null;

        }
        public bool OpenConnection()
        {
            if (_com == null)
                return false;
            try
            {
                _com.Open();
                return true;
            }
            catch (Exception ee)
            {
                System.Windows.Forms.MessageBox.Show("系统异常，打开失败！\n" + ee.Message);
                return false;
            }

        }
        public void CloseConnection()
        {
            if (_com == null)
                return;
            try
            {
                _com.Close();
            }
            catch (Exception)
            {

            }

        }
        public int BaudRate
        {
            get
            {
                return (_com != null) ? _com.BaudRate : 0;
            }
        }

        public mySerialPort()
        {
            this._com = new SerialPort();
            _usingQueue = false;
            if (_data == null)
                _data = new List<byte>();
            _data.Clear();
        }
        public mySerialPort(bool rts, bool dtr, string comName, int baudRate, int dataBits, Parity parity, StopBits stopbits, SerialPortOutputDelegate _outHandle)
        {
            if (this._com != null)
            {
                if (this._com.IsOpen) // Openning
                {
                    this._com.Close();
                }
                this._com.Dispose();
            }

            this._com = new SerialPort();
            this._com.RtsEnable = rts;
            this._com.DtrEnable = dtr;

            _com.RtsEnable = false;

            _com.PortName = comName;
            _com.BaudRate = baudRate;
            _com.DataBits = dataBits;
            _com.Parity = parity;
            _com.StopBits = stopbits;

            this._com.DataReceived += ReceiveHandler;
            _usingQueue = false;

            _serialPortOutputHander = new MySerialPort.ClassFiles.mySerialPort.SerialPortOutputDelegate(_outHandle);

            if (_data == null)
                _data = new List<byte>();
            _data.Clear();

            if (_msgBuffer == null)
                _msgBuffer = new List<byte>();
            _msgBuffer.Clear();

            //if (_msgQueue == null)
            //    _msgQueue = new Queue<List<byte>>();
            //_msgQueue.Clear();


        }


        public List<byte> GetData()
        {
            lock (ReceiveBufferLock)
            {
                List<byte> data = _data;
                _data.Clear();
                return data;
            }
        }
        public List<byte> GetData(int length)
        {
            lock (ReceiveBufferLock)
            {
                List<byte> data = new List<byte>();
                if (length <= _data.Count)
                {
                    for (int i = 0; i < length; i++)
                    {
                        data.Add(_data[0]);
                        _data.RemoveAt(0);
                    }
                }
                return data;
            }
        }
        private void ReceiveHandler(object sender, SerialDataReceivedEventArgs e)
        {
            lock (ReceiveBufferLock)
            {
                byte[] _temporary = new byte[_com.BytesToRead];
                _com.Read(_temporary, 0, _temporary.Length);
                
                if (!_usingQueue)
                {
                    lock (ReceiveBufferLock)
                    {
                       // _data.AddRange(_temporary);
                        if (_serialPortOutputHander != null)
                        {
                            _serialPortOutputHander.Invoke(_temporary);
                        }
                    }
                }
                else
                {
                    _msgBuffer.AddRange(_temporary);
                    //至少包含帧头（2字节）、长度（2字节）、目标地址（2字节）、源地址（2字节）、指令（1字节）、指令参数（1字节）、数据区、校验位（1字节）；根据设计不同而不同
                    // EA,EF(Header) L1,L2 (Little-endian) 00(Destination Address) 00(Source Address) 00(Instruct) 00 Arguments ******(Data)
                    while (_msgBuffer.Count >= 4)
                    {
                        //2.1 查找数据头
                        if (_msgBuffer[0] == 0xEA && _msgBuffer[1] == 0xFA) //传输数据有帧头，用于判断
                        {
                            int len = _msgBuffer[2] | _msgBuffer[3] << 8;
                            if (_msgBuffer.Count < len) //数据区尚未接收完整
                            {
                                break;
                            }
                            byte crc = 0;
                            foreach (byte item in _msgBuffer)
                            {
                                crc = MyUtility.CRC.CRC8CalculateByte(crc, item);
                            }
                            if (crc == 0)
                            {                              
                                lock (ReceiveBufferLock)
                                { 
                                    _data.Clear();
                                    for (int i = 0; i < len; i++)
                                    {
                                        _data.Add(_msgBuffer[i]);
                                    }
                                }
                            }
                            _msgBuffer.RemoveRange(0, len);
                            /////执行其他代码，对数据进行处理。
                            if (_serialPortOutputHander != null)
                            {
                                _serialPortOutputHander.Invoke(_data);
                               
                            }

                        }
                        else //帧头不正确时，记得清除
                        {
                            _msgBuffer.RemoveAt(0);
                        }
                    }
                }
            }
        }

        public bool ForwardBytes(byte[] _content)
        {
            
            if (_com.IsOpen)
            {
                _com.Write(_content, 0, _content.Length);
                return true;
            }
            else
            {
                return false;
            }
        }

        #region // Search Serialport Name
        /// <summary>
        /// 枚举win32 api
        /// </summary>
        private enum HardwareEnum
        {
            // 硬件
            Win32_Processor, // CPU 处理器
            Win32_PhysicalMemory, // 物理内存条
            Win32_Keyboard, // 键盘
            Win32_PointingDevice, // 点输入设备，包括鼠标。
            Win32_FloppyDrive, // 软盘驱动器
            Win32_DiskDrive, // 硬盘驱动器
            Win32_CDROMDrive, // 光盘驱动器
            Win32_BaseBoard, // 主板
            Win32_BIOS, // BIOS 芯片
            Win32_ParallelPort, // 并口
            Win32_SerialPort, // 串口
            Win32_SerialPortConfiguration, // 串口配置
            Win32_SoundDevice, // 多媒体设置，一般指声卡。
            Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
            Win32_USBController, // USB 控制器
            Win32_NetworkAdapter, // 网络适配器
            Win32_NetworkAdapterConfiguration, // 网络适配器设置
            Win32_Printer, // 打印机
            Win32_PrinterConfiguration, // 打印机设置
            Win32_PrintJob, // 打印机任务
            Win32_TCPIPPrinterPort, // 打印机端口
            Win32_POTSModem, // MODEM
            Win32_POTSModemToSerialPort, // MODEM 端口
            Win32_DesktopMonitor, // 显示器
            Win32_DisplayConfiguration, // 显卡
            Win32_DisplayControllerConfiguration, // 显卡设置
            Win32_VideoController, // 显卡细节。
            Win32_VideoSettings, // 显卡支持的显示模式。

            // 操作系统
            Win32_TimeZone, // 时区
            Win32_SystemDriver, // 驱动程序
            Win32_DiskPartition, // 磁盘分区
            Win32_LogicalDisk, // 逻辑磁盘
            Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
            Win32_LogicalMemoryConfiguration, // 逻辑内存配置
            Win32_PageFile, // 系统页文件信息
            Win32_PageFileSetting, // 页文件设置
            Win32_BootConfiguration, // 系统启动配置
            Win32_ComputerSystem, // 计算机信息简要
            Win32_OperatingSystem, // 操作系统信息
            Win32_Startup_comand, // 系统自动启动程序
            Win32_Service, // 系统安装的服务
            Win32_Group, // 系统管理组
            Win32_GroupUser, // 系统组帐号
            Win32_UserAccount, // 用户帐号
            Win32_Process, // 系统进程
            Win32_Thread, // 系统线程
            Win32_Share, // 共享
            Win32_NetworkClient, // 已安装的网络客户端
            Win32_NetworkProtocol, // 已安装的网络协议
            Win32_PnPEntity,//all device
        }
        /// <summary>
        /// WMI取硬件信息
        /// </summary>
        /// <param name="hardType"></param>
        /// <param name="propKey"></param>
        /// <returns></returns>
        private string[] MulGetHardwareInfo(HardwareEnum hardType, string propKey)
        {
            List<string> strs = new List<string>();
            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
                        if (hardInfo.Properties[propKey].Value != null && hardInfo.Properties[propKey].Value.ToString().Contains("COM"))
                        {
                            strs.Add(hardInfo.Properties[propKey].Value.ToString());
                        }

                    }
                    searcher.Dispose();
                }

                return strs.ToArray();
            }
            catch
            {
                return strs.ToArray();
            }
        }

        /// <summary>
        /// 串口信息
        /// </summary>
        /// <returns></returns>
        public string[] GetSerialPort()
        {
            //return MulGetHardwareInfo(HardwareEnum.Win32_PnPEntity, "Name");      
            return SerialPort.GetPortNames();
        }

        #endregion

        //public void Dispose()
        //{
        //    throw new NotImplementedException();
        //}
    }
}
